﻿#region Using Statemens
using System;
using System.Collections.Generic;
using System.Diagnostics;
using GameBase.Screens;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StarFox.ScreenComponents;
using StarFox.Sounds;
#endregion

namespace StarFox.Screens
{
    /// <summary>
    /// Quit menu screen of the game.
    /// </summary>
    public class QuitScreen : StarFoxScreen
    {
        #region Fields

        // unload screen content only when actually exiting the current gameplay
        bool toExit = false;
        
        GamePlaySound sound;
        
        #endregion

        #region Screen Transitions

        bool toHidden = false;

        float trTime = 0.0f;

        /// <summary>
        /// Makes the Screen transition to hidden state.
        /// </summary>
        public override void Hide()
        {
            toHidden = true;

            base.Hide();
        }

        #endregion

        #region Initialization

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="screenManager">The ScreenManager that this Screen is associated to.</param>
        public QuitScreen(ScreenManager screenManager)
            : base(screenManager)
        {
            Name = "QuitScreen";
        }

        /// <summary>
        /// Called when the Screen needs to be initialized.
        /// </summary>
        public override void Initialize()
        {
            sound = Game.Services.GetService(typeof(GamePlaySound)) as GamePlaySound;
            if (sound == null)
                throw new InvalidOperationException("Service of type StarFoxSound not found");

            Components3D.Add(new MenuBackground(this) { Duration = TimeSpan.FromSeconds(6) });

            ApplicationMenu menu = new ApplicationMenu(this);
            // menu title
            menu.MenuTitle = "TITLE_QUIT_MENU";
            // menu items
            List<ApplicationMenu.IMenuItem> auxMenuItems = new List<ApplicationMenu.IMenuItem>();
            auxMenuItems.Add(new ApplicationMenu.LinkItem("ITEM_YES", new ApplicationMenu.ButtonMessage[] { ApplicationMenu.ButtonMessage.SELECT, ApplicationMenu.ButtonMessage.BACK }));
            auxMenuItems.Add(new ApplicationMenu.LinkItem("ITEM_NO", new ApplicationMenu.ButtonMessage[] { ApplicationMenu.ButtonMessage.SELECT, ApplicationMenu.ButtonMessage.BACK }));
            menu.MenuItems = auxMenuItems;
            // by default select "NO"
            menu.SelectedItem = 1;
            // menu actions
            menu.MenuAccept += (sender, args) =>
            {
                #region Menu Actions

                switch (args.Index)
                {
                    case 0:
                        // yes
                        ScreenManager.Clear(new PresentationScreen(ScreenManager));
                        toExit = true;
                        sound.StopAllSounds();
                        break;
                    case 1:
                        // no
                        ScreenManager.RemoveScreen(this);
                        break;
                    default:
                        break;
                }

                #endregion
            };

            Components2D.Add(menu);
            Components2D.Add(new QuitMessage(this));        

            base.Initialize();
        }

        #endregion

        #region Update

        /// <summary>
        /// Called when the Screen needs to be updated.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        public override void Update(GameTime gameTime)
        {
            #region Screen Transition

            if (toHidden)
            {
                // update transition timer
                float trDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / Time.TotalMilliseconds);
                trTime += trDelta;
                trTime = MathHelper.Clamp(trTime, 0.0f, 1.0f);
                if (trTime == 1.0f)
                {
                    toHidden = false; trTime = 0.0f;
                    if (toExit) { PlayList.Stop(); ScreenSound.LoadGame(); }
                }
            }

            #endregion

            base.Update(gameTime);
        }

        #endregion

        #region Dispose

        // dispose flag
        bool isDisposed = false;

        /// <summary>
        /// Releases the unmanaged resources used by this object and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
            if (!isDisposed)
            {
                if (disposing)
                {
                    // unload screen content only when actually exiting the current gameplay
                    if (toExit) { Content.Unload(); }

                    base.Dispose(disposing);
                }

                isDisposed = true;
            }
        }

        #endregion
    }

    #region Quit Message

    /// <summary>
    /// Flashing message for quit menu screen.
    /// </summary>
    public class QuitMessage : ScreenComponent2D, IDisposable
    {
        #region Fields

        // quit message
        SpriteFont bigFont;
        SpriteFont smallFont;
        Vector2 msgPos_01;
        Vector2 msgPos_02;

        // flashing effect
        float messageAlpha = 1.0f;
        bool toInvisible = true;
        TimeSpan totalFadeTime = TimeSpan.FromMilliseconds(500);
        float fadeTime = 0.0f;

        // background
        Texture2D bkgTex;
        Rectangle bkgRect;

        #endregion

        #region Screen Transitions

        /// <summary>
        /// Makes the ScreenComponent2D transition to visible state.
        /// </summary>
        public override void Show()
        {
            // make the message transition to visible when the screen is showing
            messageAlpha = 0.0f;
            toInvisible = false;
            fadeTime = 0.0f;
        }

        /// <summary>
        /// Makes the ScreenComponent2D transition to hidden state.
        /// </summary>
        public override void Hide() 
        { 
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="screen">The Screen that this ScreenComponent2D is associated to.</param>
        public QuitMessage(StarFoxScreen screen)
            : base(screen)
        {
            // quit message
            bigFont = Game.Content.Load<SpriteFont>(ContentSettings.GetAsset("FONT_BIG"));
            smallFont = Game.Content.Load<SpriteFont>(ContentSettings.GetAsset("FONT_SMALL"));
            msgPos_01 = new Vector2(Screen.Width * 0.10f, Screen.Height * 0.475f);
            msgPos_02 = new Vector2(Screen.Width * 0.10f, Screen.Height * 0.55f);

            // background
            bkgTex = new Texture2D(Screen.GraphicsDevice, 1, 1);
            bkgTex.SetData(new[] { new Color(51, 51, 51, 191) });
            bkgRect = new Rectangle(0, (int)(Screen.Height * 0.450f), Screen.Width, (int)(Screen.Height * 0.175f));
        }

        #endregion
        
        #region Dispose

        // dispose flag
        bool isDisposed = false;

        /// <summary>
        /// Immediately releases all resources used by this object.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection.
        /// </summary>
        ~QuitMessage()
        {
            Dispose(false);
        }

        /// <summary>
        /// Releases the unmanaged resources used by this object and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!isDisposed)
            {
                if (disposing)
                {
                    if (bkgTex != null) { bkgTex.Dispose(); bkgTex = null; }
                }

                isDisposed = true;
            }
        }

        #endregion

        #region Update

        /// <summary>
        /// Called when the ScreenComponent2D needs to be updated.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        public override void Update(GameTime gameTime)
        {
            // update the alpha channel of the message color
            if (toInvisible)
            {
                float fadeDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / totalFadeTime.TotalMilliseconds);
                fadeTime += fadeDelta;
                fadeTime = MathHelper.Clamp(fadeTime, 0.0f, 1.0f);
                messageAlpha = (float)Math.Pow(1.0f - fadeTime, 2);
                if (fadeTime == 1.0f) { toInvisible = false; fadeTime = 0.0f; }
            }
            else
            {
                float fadeDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / totalFadeTime.TotalMilliseconds);
                fadeTime += fadeDelta;
                fadeTime = MathHelper.Clamp(fadeTime, 0.0f, 1.0f);
                messageAlpha = (float)Math.Pow(fadeTime, 2);
                if (fadeTime == 1.0f) { toInvisible = true; fadeTime = 0.0f; }
            }
        }

        #endregion

        #region Draw

        /// <summary>
        /// Called when the ScreenComponent2D needs to be drawn.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        public override void Draw(GameTime gameTime)
        {
            // background
            SpriteBatch.Draw(bkgTex, bkgRect, Color.Yellow);

            // quit message
            SpriteBatch.DrawString(bigFont, "WARNING", msgPos_01, Color.Red * messageAlpha, 0, Vector2.Zero, Screen.Scale, SpriteEffects.None, 0);
            SpriteBatch.DrawString(smallFont, "!! ANY CURRENT PROGRESS WILL BE LOST", msgPos_02, Color.Red, 0, Vector2.Zero, Screen.Scale, SpriteEffects.None, 0);
        }

        #endregion
    }

    #endregion
}